﻿#!/usr/bin/env python2.5
"""Ce script extrait les classes des fichiers .php passes en argument
Il recherche :
  class [nom_classe] extends [nom_parent]
  (var|private) $[nom_attribut]
  function [nom_fonction]
Il affiche ensuite le script yUML.me des classes
"""

__author__ = "Emmanuel DENIS"
__version__ = "$Revision: 0.1 $"
__date__ = "$Date: 2010/02/03 $"

import sys
import re
import codecs


class Classe(object):
  """Une classe avec ses methodes : add_attribut & add_methode.

  Utilisation :
  >>> m = Classe("Someone") # une classe sans rien d'autre
  >>> print m # affiche le nom de la classe
  classe : Someone
  >>> z = Classe("Child","Parent")
  >>> print z # affiche le nom de la classe et son parent
  classe : Child
  parent : Parent
  >>> z.add_attribut("age")
  >>> print z # affiche le nom, parent et un attribut
  classe : Child
  parent : Parent
  attributs : ['age']
  """
  def __init__(self, nom, parent=""):
    self.nom = nom
    self.parent = parent
    self.attributs = []
    self.methodes = []

  def __str__( self ):
    texte = "classe : " + self.nom
    if self.parent != "":
      texte += "\nparent : " + self.parent
    if self.attributs != []:
      texte += "\nattributs : " + str(self.attributs)
    if self.methodes != []:
      texte += "\nmethodes : " + str(self.methodes)
    return texte

  def add_attribut( self, nom_attribut ):
    #print "on ajoute l'attribut %s a %s" % (nom_attribut, self.nom)
    self.attributs.append(nom_attribut)

  def add_methode( self, nom_methode ):
    #print "on ajoute la methode %s a %s" % (nom_methode, self.nom)
    self.methodes.append(nom_methode)

  def get_yuml_script( self ):
    """renvoie le script yUML de la classe

    Utilisation :
    >>> z = Classe("Child","Parent")
    >>> z.add_attribut("age")
    >>> z.add_methode("wish_happy_birthday")
    >>> print z.get_yuml_script()
    [Parent]^[Child|age|wish_happy_birthday]
    """
    # on construit les differents elements :
    # - son parent (vide par defaut)
    parent = ""
    if self.parent != "":
      parent = "[%s]^" % self.parent
    # - sa liste d'attributs
    liste_attributs = ";".join(self.attributs)
    # - sa liste de methodes
    liste_methodes = ";".join(self.methodes)
    #
    return parent + "[%s|%s|%s]" % (self.nom, liste_attributs, liste_methodes)


def main():
  if sys.argv[1:]:
    classes = {} # init du dico
    # pour chaque fichier passe en argument au script
    for fichier in sys.argv[1:]:
      # ouverture du fichier
      contenu = codecs.open(fichier,"r","utf-8").readlines()
      # pour chaque ligne du fichier
      for line in contenu:
        match_class = re.search("^\s*class (?P<nom>\w+)", line,
                                flags=re.UNICODE)
        if( match_class ): # nous sommes en presence d'une nouvelle classe
          # on tente d'ajouter la classe existante a la liste des classes
          # TODO(ED) trouver un autre moyen de faire ça
          try:
            classes[nom_classe] = classe
          except:
            pass

          # on commence une nouvelle classe
          nom_classe = match_class.group('nom')
          # on reset les variables utilisees
          nom_parent = ""

          # a-t-elle un parent ?
          match_extends = re.search(" extends (?P<parent>\w+)", line,
                                    flags=re.UNICODE)
          if match_extends:
            nom_parent = match_extends.group('parent')

          # on cree donc un objet classe
          classe = Classe(nom_classe, nom_parent)
          #print "on vient de creer la classe " + nom_classe

        # decouverte d'attribut
        match_attr = re.search("(var|private) \$(?P<nom_variable>\w+)", line,
                               flags=re.UNICODE)
        if( match_attr ):
          #print match_attr.group('nom_variable')
          if( classe is None):
            pass
          else:
            classe.add_attribut( match_attr.group('nom_variable') )

        # decouverte de methode
        match_meth = re.search("function (?P<nom_methode>\w+)", line,
                               flags=re.UNICODE)
        if( match_meth ):
          #print match_meth.group('nom_methode')
          classe.add_methode( match_meth.group('nom_methode') )

    # n'oublions pas, eventuellement, la dernier classe creee
    # TODO(ED) trouver un autre moyen de faire ça
    try:
      classes[nom_classe] = classe
    except:
      pass

    print "\nVoici le script yUML.me des classes :\n"
    yUML_script = ""
    for key, classe in classes.iteritems():
      # on concatene leur script YUML.me avec des virgule
      yUML_script += "," + classe.get_yuml_script()

    # mais on ne prend pas la première virgule
    yUML_script = yUML_script[1:]
    print yUML_script

  else:
    # affiche la documentation du script
    print __doc__


if __name__ == "__main__":
  main()
